package com.edushare.common.dao.academics.grades;

import java.util.Date;
import java.util.List;

import com.edushare.common.dao.CayenneBasedDAO;
import com.edushare.common.dao.CoursesDAO;
import com.edushare.common.dao.DepartmentsDAO;
import com.edushare.common.orm.ORMInterface;
import com.edushare.common.vo.Assignments;
import com.edushare.common.vo.CourseGrade;
import com.edushare.common.vo.CourseInstances;
import com.edushare.common.vo.GradeKey;
import com.edushare.common.vo.GradingItem;
import com.edushare.common.vo.ItemGrade;
import com.edushare.common.vo.Universities;
import com.edushare.common.vo.Users;

public class InternalGrades extends CayenneBasedDAO {

	public static final int OPERATION_OK 								= 0;
	public static final int STUDENT_MARKS_GREATER_THAN_MAX 				= 1;
	public static final int COURSE_MAX_MARKS_LESS_THAN_STUDENT_MARKS 	= 2;
	public static final int COURSE_ITEM_GRADES_NA						= 3;

	public static final String[] str = {
		"",
		"The marks you entered for students are greater than maximum marks for this item.",
		"Cannot reset the maximum marks as some students' marks are greater than this.",
		"All assignments, examinations and tests should be evaluated before calculating grades"
	};

	public InternalGrades(ORMInterface ormInterface) {
		super(ormInterface);
	}

	public boolean useLetterGrades(CourseInstances course) {
		Universities univ = new DepartmentsDAO(ormInterface)
				.getParent(new CoursesDAO(ormInterface).getParentDept(course
						.getCourse()));
		return new UnivLetterGrades(ormInterface).hasLetterGrades(univ);
	}
	
	public GradingItem addNewComponent(CourseInstances cInst, String desc,
			String name, int itemType, double maxMarks, double weightage) {
		GradingItem g = new GradingItem();
		g.setAssignment(null);
		g.setCourseInstance(cInst);
		g.setCreationDate(new Date());
		g.setGradeType(0);
		g.setGradingItemDesc(desc);
		g.setGradingItemName(name);
		g.setItemType(itemType);
		g.setMaxMarks(maxMarks);
		g.setWeightage(weightage);
		getDataContext().registerNewObject(g);
		return g;
	}

	public GradingItem addNewComponent(CourseInstances cInst,
			Assignments assgn, String desc, String name, int itemType,
			double maxMarks, double weightage) {
		GradingItem g = new GradingItem();
		g.setAssignment(assgn);
		g.setCourseInstance(cInst);
		g.setCreationDate(new Date());
		g.setGradeType(0);
		g.setGradingItemDesc(desc);
		g.setGradingItemName(name);
		g.setItemType(itemType);
		g.setMaxMarks(maxMarks);
		g.setWeightage(weightage);
		getDataContext().registerNewObject(g);
		return g;
	}

	public int editComponentRange(GradingItem gItem, double maxMarks) {
		if (maxMarks >= gItem.getMaxMarks()) {
			gItem.setMaxMarks(maxMarks);
			return OPERATION_OK;
		}
		return COURSE_MAX_MARKS_LESS_THAN_STUDENT_MARKS;
	}

	public ItemGrade getStudentMarksItem(Users u, GradingItem item) {
		List<ItemGrade> list = u.getGrades();
		for (ItemGrade ig : list) {
			if (ig.getGradingItem() == item)
				return ig;
		}
		return null;
	}

	public double getStudentMarks(Users u, GradingItem item) {
		ItemGrade ig = getStudentMarksItem(u, item);
		if (ig != null)
			return ig.getMarks();
		return 0.0;
	}

	public int setStudentCompMarks(Users u, GradingItem g, double marks,
			String comments) {
		if (marks > g.getMaxMarks())
			return STUDENT_MARKS_GREATER_THAN_MAX;
		ItemGrade it = getStudentMarksItem(u, g);
		if (it == null) {
			it = new ItemGrade();
			getDataContext().registerNewObject(it);
			it.setGradeKey(null);
			it.setGradingItem(g);
			it.setUser(u);
		}
		it.setComments(comments);
		it.setMarks(marks);
		getDataContext().commitChanges();
		return OPERATION_OK;
	}

	public void removeStudentCompMarks(Users u, GradingItem item) {
		ItemGrade it = getStudentMarksItem(u, item);
		if (it != null)
			getDataContext().deleteObject(it);
		getDataContext().commitChanges();
	}

	public int recalculateCGPA(CourseInstances courseInst, Users u) {
		CourseGrade grade = getStudentCourseGrade(courseInst, u);
		if (grade != null && grade.getManualEntry() == CourseGrade.MANUAL_ENTRY)
			return OPERATION_OK;

		List<GradingItem> itemList = courseInst.getGradingItems();
		double total = 0;
		double weightage = 0;
		for (GradingItem item : itemList) {
			ItemGrade g = getStudentMarksItem(u, item);
			if (g == null && item.getWeightage() >= 0.01)
				return COURSE_ITEM_GRADES_NA;
			double marks = (g.getMarks() * 100) / item.getMaxMarks();
			total += (marks * item.getWeightage());
			weightage += item.getWeightage();
		}
		total /= weightage;
		total = Math.floor(total * 100);
		total /= 100;

		CourseGrade cg = getStudentCourseGrade(courseInst, u);
		if (cg == null) {
			cg = new CourseGrade();
			cg.setCourse(courseInst);
			cg.setUser(u);
			getDataContext().registerNewObject(cg);
			cg.setManualEntry(CourseGrade.CALCULATED_ENTRY);
		}
		cg.setComments("");
		cg.setMarks(total);
		if (useLetterGrades(courseInst)) {
			cg.setEvaluationType(CourseGrade.EVAL_GRADE);
			cg.setGradeKey(new LetterGradeMap(ormInterface).getGradeKey(
					courseInst, total));
		} else {
			cg.setEvaluationType(CourseGrade.EVAL_MARKS);
		}

		getDataContext().commitChanges();
		return OPERATION_OK;
	}

	public CourseGrade getStudentCourseGrade(CourseInstances course, Users u) {
		List<CourseGrade> cgList = u.getCourseGrades();
		for (CourseGrade cg : cgList) {
			if (cg.getCourse() == course)
				return cg;
		}
		return null;
	}

	public void removeCourseGrade(CourseInstances course, Users u) {
		CourseGrade cg = getStudentCourseGrade(course, u);
		if (cg != null)
			getDataContext().deleteObject(cg);
		getDataContext().commitChanges();
	}

	public void setCourseGrade(CourseInstances course, Users u,
			String comments, GradeKey key, double marks) {
		CourseGrade cg = getStudentCourseGrade(course, u);
		if (cg == null) {
			cg = new CourseGrade();
			cg.setCourse(course);
			cg.setUser(u);
			getDataContext().registerNewObject(cg);
		}
		cg.setComments(comments);
		cg.setManualEntry(CourseGrade.MANUAL_ENTRY);
		if(useLetterGrades(course)){
			cg.setEvaluationType(CourseGrade.EVAL_GRADE);
			cg.setGradeKey(key);
			cg.setMarks(marks);
		}else{
			cg.setEvaluationType(CourseGrade.EVAL_MARKS);
			cg.setMarks(marks);
			cg.setGradeKey(null);
		}
		getDataContext().commitChanges();
	}
}
